
package com.taoyuanx.boot.conf;

import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.json.JSONException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.NoHandlerFoundException;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.alibaba.fastjson.support.config.FastJsonConfig;
import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
import com.taoyuanx.boot.common.HeaderIncepter;
import com.taoyuanx.boot.common.Result;
import com.taoyuanx.boot.common.ResultBuilder;
import com.taoyuanx.boot.eum.ResultCode;
import com.taoyuanx.boot.exception.ServiceException;
import com.taoyuanx.boot.exception.ValidatorException;
import com.taoyuanx.boot.utils.StrUtil;
import com.taoyuanx.boot.version.DefaultApiVersionCodeDiscoverer;
import com.taoyuanx.boot.version.MultiVersionRequestMappingHandlerMapping;



/**
 * @author 都市桃源
 *
 */
@Configuration
public class WebMvcConfig extends WebMvcConfigurationSupport {

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/static/**").addResourceLocations("classpath:/static/");
    }
    public static final Logger log=LoggerFactory.getLogger(WebMvcConfig.class);
	@Autowired 
	HeaderIncepter headerIncepter;
    @Bean
    @Override
    public RequestMappingHandlerMapping requestMappingHandlerMapping() {
    	  MultiVersionRequestMappingHandlerMapping handlerMapping = new MultiVersionRequestMappingHandlerMapping();
    	  handlerMapping.registerApiVersionCodeDiscoverer(new DefaultApiVersionCodeDiscoverer());
    	  handlerMapping.setOrder(0);
    	  handlerMapping.setInterceptors(getInterceptors());
    	  handlerMapping.setContentNegotiationManager(mvcContentNegotiationManager());
    	  return handlerMapping;
    }
    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
       
        //1.需要定义一个convert转换消息的对象;
        FastJsonHttpMessageConverter fastJsonHttpMessageConverter = new FastJsonHttpMessageConverter();
        //2.添加fastJson的配置信息，比如：是否要格式化返回的json数据;
        FastJsonConfig fastJsonConfig = new FastJsonConfig();
        fastJsonConfig.setSerializerFeatures(SerializerFeature.PrettyFormat);
        //3处理中文乱码问题
        List<MediaType> fastMediaTypes = new ArrayList<>();
        fastMediaTypes.add(MediaType.APPLICATION_JSON);
        fastJsonConfig.setCharset(Charset.forName("UTF-8"));
        //4.在convert中添加配置信息.
        fastJsonHttpMessageConverter.setSupportedMediaTypes(fastMediaTypes);
        fastJsonHttpMessageConverter.setFastJsonConfig(fastJsonConfig);
        //5.将convert添加到converters当中.
        converters.add(fastJsonHttpMessageConverter);
        super.configureMessageConverters(converters);
    }
	@Override
	protected void addInterceptors(InterceptorRegistry registry) {
		registry.addInterceptor(headerIncepter);
		super.addInterceptors(registry);
	}
	 //统一异常处理
    @Override
    public void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> exceptionResolvers) {
        exceptionResolvers.add(new HandlerExceptionResolver() {
            public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception e) {
              	Result result=new Result();
            	result.setStatus(ResultCode.FAIL.code);
            	if(e instanceof ValidatorException){//参数异常
                	result =ResultBuilder.failBuilder()
        					.buildCode(ResultCode.PARAM_ERROR.code)
        					.buildMsg(e.getMessage())
        					.build();
            		responseResult(response, result);
            		return new ModelAndView();
                }else if (e instanceof ServiceException) {//业务失败的异常，如“账号或密码错误”
            		ServiceException serviceException=(ServiceException) e;
            		result.setCode(serviceException.code);
            		result.setMsg(serviceException.getMessage());
            		responseResult(response, result);
            		return new ModelAndView();
                } else if (e instanceof NoHandlerFoundException) {//404
                	result.setCode(ResultCode.NOT_FOUND.code);
            		result.setMsg( "接口 [" +( (NoHandlerFoundException) e).getRequestURL() + "] 不存在");
            		responseResult(response, result);
            		return new ModelAndView();
                }else if(e instanceof JSONException){//json格式不合法
					result.setCode(ResultCode.PARAM_ERROR.code);
            		result.setMsg( "参数不符合json标准,"+e.getMessage());
            		responseResult(response, result);
            		return new ModelAndView();
                }else if (e instanceof ServletException) {//内部异常
                    result.setCode(ResultCode.INTERNAL_SERVER_ERROR.code);
            		result.setMsg(e.getMessage());
            		responseResult(response, result);
            		return new ModelAndView();
                }else {//未知异常
                	result.setCode(ResultCode.INTERNAL_SERVER_ERROR.code);
              		result.setMsg(StrUtil.log4jFormat("接口{}未知错误，请联系管理员,管理员[{}],异常信息为{}", request.getRequestURI(),"www.taoyuanx.com",e.getMessage()));
                	HandlerMethod handlerMethod = (HandlerMethod) handler;
                    log.error("接口 [{}] 出现异常，方法：{}.{}，异常摘要：{}", 
                    		 request.getRequestURI(),
                             handlerMethod.getBean().getClass().getName(),
                             handlerMethod.getMethod().getName(),
                             e.getMessage());
                    StringWriter out = new StringWriter();
                	e.printStackTrace(new PrintWriter(out));
                	log.error("系统异常,异常信息为{}", out);
                	responseResult(response, result);
            		return new ModelAndView();
                }
                
                
            }

        });
    }

    //解决跨域问题
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**");
    }

	private void responseResult(HttpServletResponse response, Result result) {
        response.setCharacterEncoding("UTF-8");
        response.setHeader("Content-type", "application/json;charset=UTF-8");
        response.setStatus(200);
        try {
            response.getWriter().write(JSON.toJSONString(result));
        } catch (IOException ex) {
        	log.error("异常信息为{}",ex);
        }
    }
}
